package cn.amossun.starter.web.data.security.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.amossun.starter.common.util.Page;
import cn.amossun.starter.web.data.security.IDataSecurityVersion;
import cn.amossun.starter.web.data.security.entity.DataSecurityVersionBO;
import cn.amossun.starter.mybatis.data.security.properties.ResultMapConfiguration;
import cn.amossun.starter.redis.cache.exception.RedisCacheConfigException;
import cn.amossun.starter.redis.cache.exception.RedisRelatedException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: BladeX-Boot
 * @description:
 * @author: Amos.Sun
 * @DateTime: 2020/03/08 18:17
 **/
@Data
@Slf4j
public class DataSecurityVersionHandler implements IDataSecurityVersion {

	public final RedisTemplate amosMultiRedisTemplate;

	public DataSecurityVersionHandler(@Autowired(required = false) @Qualifier("amosMultiRedisTemplate") RedisTemplate amosMultiRedisTemplate) {
		this.amosMultiRedisTemplate = amosMultiRedisTemplate;
	}

	@Override
	public List<DataSecurityVersionBO> getAllRecords(String serviceName) throws RedisRelatedException, RedisCacheConfigException {
		assertService(serviceName);

		//获取服务redis数据源版本记录
		List redisResult = amosMultiRedisTemplate.opsForHash().values(getSecurityVersionKey(serviceName));
		JSONArray jsonArray = JSONUtil.parseArray(JSONUtil.toJsonStr(redisResult));
		List<DataSecurityVersionBO> securityVersionRecords = JSONUtil.toList(jsonArray, DataSecurityVersionBO.class);

		if (CollectionUtil.isEmpty(securityVersionRecords)) {
			return new ArrayList<>(0);
		}

		Collections.sort(securityVersionRecords, new Comparator<DataSecurityVersionBO>() {
			public int compare(DataSecurityVersionBO o1, DataSecurityVersionBO o2) {
				return o2.getCreateTime().compareTo(o1.getCreateTime());//降序
			}
		});
		return securityVersionRecords;
	}

	@Override
	public Page getRecords(String serviceName, int current, int size, String version) throws RedisRelatedException, RedisCacheConfigException {
		assertService(serviceName);

		List<DataSecurityVersionBO> securityVersionRecords = getAllRecords(serviceName);

		Page page = new Page();
		page.setCurrent(current);
		page.setSize(size);

		if(CollectionUtil.isEmpty(securityVersionRecords)) {
			return page;
		}

		if(StrUtil.isNotEmpty(version) && StrUtil.isNotEmpty(version.trim()) && CollectionUtil.isNotEmpty(securityVersionRecords)) {
			List result = securityVersionRecords.stream().filter(source-> source.getVersion().contains(version.trim())).collect(Collectors.toList());
			securityVersionRecords = result;
		}
		/*if(StrUtil.isNotEmpty(operatorName) && CollectionUtil.isNotEmpty(securityVersionRecords)) {
			List result = securityVersionRecords.stream().filter(source-> source.getOperatorName().contains(operatorName.trim())).collect(Collectors.toList());
			securityVersionRecords = result;
		}*/

		if (CollectionUtil.isEmpty(securityVersionRecords)) {
			return page;
		}

		//结果内存分页
		page.computeRecords(securityVersionRecords);
		return page;
	}

	@Override
	public boolean addRecords(String userId, String serviceName, List<ResultMapConfiguration> newsList) throws RedisRelatedException, RedisCacheConfigException {
		assertService(serviceName);

		//hutool md5(jsonStr+userId)  = version
		String newsJson = JSONUtil.toJsonStr(newsList);
		String newsJsonMd5 = MD5.create().digestHex(new StringBuilder(newsJson).append(userId).toString());

		DataSecurityVersionBO dataSecurityVersionBO = DataSecurityVersionBO.builder().serviceName(serviceName)
												.version(newsJsonMd5).versionValue(newsJson)
												.createTime(DateUtil.date()).userId(userId).build();

		//saveRedisDB
		amosMultiRedisTemplate.opsForHash().put(getSecurityVersionKey(serviceName), newsJsonMd5, dataSecurityVersionBO);
		return true;
	}

	@Override
	public DataSecurityVersionBO get(String serviceName, String version) throws RedisCacheConfigException, RedisRelatedException {
		List<DataSecurityVersionBO> securityVersionRecords = getAllRecords(serviceName);
		Map<String,DataSecurityVersionBO> sourceMap =
				securityVersionRecords.stream().collect(Collectors.toMap(DataSecurityVersionBO::getVersion, source->source));
		return sourceMap.get(version);
	}

	@Override
	public boolean isLastVersion(String serviceName, String version) throws RedisCacheConfigException, RedisRelatedException {
		assertVersion(serviceName, version);

		List<DataSecurityVersionBO> securityVersionRecords = getAllRecords(serviceName);
		if(CollectionUtil.isEmpty(securityVersionRecords)) {
			return false;
		}
		DataSecurityVersionBO dataSecurityVersionBO = securityVersionRecords.get(0);
		return version.equals(dataSecurityVersionBO.getVersion());
	}

	protected void assertVersion(String serviceName, String version) throws RedisCacheConfigException, RedisRelatedException {
		if(StrUtil.isEmpty(version)) {
			throw new RedisCacheConfigException("选择版本不允许为空");
		}
		DataSecurityVersionBO dataSecurityVersionBO = get(serviceName, version);
		if(dataSecurityVersionBO == null) {
			throw new RedisCacheConfigException("选择版本非法");
		}
	}

}
